package com.cosmoplat.xikai.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cosmoplat.xikai.business.domain.BaseAlarmRecord;
import com.cosmoplat.xikai.business.domain.BaseDeliveryInfo;
import com.cosmoplat.xikai.business.domain.BaseDispatchTask;
import com.cosmoplat.xikai.business.domain.dto.alarm.AlarmQueryDTO;
import com.cosmoplat.xikai.business.domain.dto.scada.DeviceFaultDto;
import com.cosmoplat.xikai.business.domain.mes.req.MesAlarmCloseRequest;
import com.cosmoplat.xikai.business.domain.mes.req.MesLineAlarmRequest;
import com.cosmoplat.xikai.business.domain.mes.result.MesResult;
import com.cosmoplat.xikai.business.domain.vo.AlarmVo;
import com.cosmoplat.xikai.business.service.BaseAlarmRecordService;
import com.cosmoplat.xikai.business.mapper.BaseAlarmRecordMapper;
import com.cosmoplat.xikai.business.service.MesRequestService;
import com.cosmoplat.xikai.common.core.domain.AjaxResult;
import com.cosmoplat.xikai.common.core.domain.entity.SysUser;
import com.cosmoplat.xikai.common.enums.business.AlarmTypeEnum;
import com.cosmoplat.xikai.common.utils.DateUtils;
import com.cosmoplat.xikai.common.utils.StringUtils;
import com.cosmoplat.xikai.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 22047582
 * @description 针对表【base_alarm_record】的数据库操作Service实现
 * @createDate 2025-01-07 13:51:29
 */
@Slf4j
@Service
public class BaseAlarmRecordServiceImpl extends ServiceImpl<BaseAlarmRecordMapper, BaseAlarmRecord> implements BaseAlarmRecordService {
    @Autowired
    private MesRequestService mesRequestService;
    @Autowired
    private ISysUserService userService;
    @Value("${device.code}")
    private String deviceCode;

    @Override
    public List<BaseAlarmRecord> queryForPage(AlarmQueryDTO query) {
        QueryWrapper<BaseAlarmRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByDesc(BaseAlarmRecord::getAlarmStartTime).orderByAsc(BaseAlarmRecord::getAlarmCode).eq(StringUtils.isNotEmpty(query.getAlarmCode()), BaseAlarmRecord::getAlarmCode, query.getAlarmCode()).eq(StringUtils.isNotEmpty(query.getAlarmName()), BaseAlarmRecord::getAlarmName, query.getAlarmName()).eq(query.getAlarmType() != null, BaseAlarmRecord::getAlarmType, query.getAlarmType()).between(query.getStartTime() != null && query.getEndTime() != null, BaseAlarmRecord::getAlarmStartTime, query.getStartTime(), query.getEndTime());
        return list(queryWrapper);
    }

    @Override
    public AlarmVo createAlarmVo(AlarmVo alarmVo) {
        save(alarmVo);
        return alarmVo;
    }

    @Override
    public void shortMaterialCallMes(BaseDispatchTask doingTask, BaseDeliveryInfo deliveryInfo, AlarmVo alarmRecord) {
        callMesAlarm(doingTask, deliveryInfo, alarmRecord, MesLineAlarmRequest.MesExceptionType.MATERIAL);
    }

    @Override
    public void qualityExceptionCallMes(BaseDispatchTask doingTask, String materialCode, String alarmContent, String productId) {
        // 已存在告警记录，不重复告警
        if (CollectionUtils.isNotEmpty(getNotCloseAlarm(materialCode, AlarmTypeEnum.QUALITY_EXCEPTION, productId))) {
            log.info("物料：{} 已存在质量告警记录，不重复告警", materialCode);
            return;
        }

        AlarmVo alarmVo = new AlarmVo();
        alarmVo.setEquipmentCode(deviceCode);
        alarmVo.setAlarmCode(DateUtils.dateTimeNow());
        alarmVo.setAlarmName(materialCode + "质量异常");
        alarmVo.setAlarmType(AlarmTypeEnum.QUALITY_EXCEPTION.getCode());
        alarmVo.setAlarmContent(alarmContent);
        alarmVo.setAlarmStartTime(new Date());
        alarmVo.setMaterialCode(materialCode);
        alarmVo.setBusinessInfo(productId);
        AlarmVo alarmPo = createAlarmVo(alarmVo);

        // 通知mes告警
        callMesAlarm(doingTask, null, alarmPo, MesLineAlarmRequest.MesExceptionType.QUALITY);
    }

    @Override
    public void materialErrorCallMes(BaseDispatchTask doingTask, String materialCode, String alarmContent) {
        // 已存在告警记录，不重复告警   - 告警错误不需要去重
        /*if (CollectionUtils.isNotEmpty(getAlarmingByMaterialCode(materialCode, AlarmTypeEnum.MATERIAL_ERROR))) {
            log.info("物料：{} 已存在物料错误告警记录，不重复告警", materialCode);
            return;
        }*/
        AlarmVo alarmVo = new AlarmVo();
        alarmVo.setEquipmentCode(deviceCode);
        alarmVo.setAlarmCode(DateUtils.dateTimeNow());
        alarmVo.setAlarmName(materialCode + "物料错误");
        alarmVo.setAlarmType(AlarmTypeEnum.MATERIAL_ERROR.getCode());
        alarmVo.setAlarmContent(alarmContent);
        alarmVo.setAlarmStartTime(new Date());
        alarmVo.setAlarmEndTime(new Date());
        alarmVo.setMaterialCode(materialCode);
        AlarmVo alarmPo = createAlarmVo(alarmVo);

        // 通知mes告警
        callMesAlarm(doingTask, null, alarmPo, MesLineAlarmRequest.MesExceptionType.MATERIAL);
    }


    @Override
    public void callMesAlarm(BaseDispatchTask doingTask, BaseDeliveryInfo deliveryInfo, AlarmVo alarmRecord, MesLineAlarmRequest.MesExceptionType enumType) {
        MesLineAlarmRequest alarm = new MesLineAlarmRequest();
        alarm.setOrderID(doingTask.getTaskId());
        alarm.setTaskID(doingTask.getTaskId());
        alarm.setId(String.valueOf(alarmRecord.getId()));
        if (deliveryInfo != null) {
            alarm.setProcessNo(deliveryInfo.getProcessCode());
        } else {
            alarm.setProcessNo(doingTask.getProcessCode());
        }
        alarm.setAlarmCode(alarmRecord.getAlarmCode());
        alarm.setDeviceInfo(alarmRecord.getAlarmContent());
        alarm.setExceptionType(enumType.getCode());
        alarm.setExceptionInfo(alarmRecord.getAlarmContent());
        alarm.setSender(doingTask.getOperator());
        log.info("告警请求：{}", alarm);
        MesResult<Void> mesResult = mesRequestService.alarm(alarm);
        if (!mesResult.isSuccess()) {
            log.error("告警请求-同步mes数据异常, 发生内容，{} 返回内容：{}", alarm, mesResult);
        }
        log.info("告警请求-同步mes数据成功，返回内容：{}", mesResult);
    }

    @Override
    public void stopAlarm(BaseDispatchTask doingTask, String materialCode, AlarmTypeEnum alarmTypeEnum, String businessInfo) {
        List<BaseAlarmRecord> alarmRecord = getNotCloseAlarm(materialCode, alarmTypeEnum, businessInfo);
        if (alarmRecord.isEmpty()) {
            log.debug("物料：{} 业务字段：{} 不存在告警记录，未关闭", materialCode, businessInfo);
            return;
        }
        for (BaseAlarmRecord record : alarmRecord) {
            log.info("告警关闭，原告警内容：{}", record.getAlarmContent());
            // 更新完成时间
            record.setAlarmEndTime(new Date());
            updateById(record);

            // mes 不需要调用该接口关闭告警
            /*MesAlarmCloseRequest alarmClose = new MesAlarmCloseRequest();
            alarmClose.setTaskID(doingTask.getTaskId());
            MesAlarmCloseRequest.HandleInfo handleInfo = new MesAlarmCloseRequest.HandleInfo();
            handleInfo.setStartTime(record.getAlarmStartTime());
            handleInfo.setEndTime(record.getAlarmEndTime());
            // TODO 确认mes 用户信息 的id 怎么传值
            //handleInfo.setUserId(doingTask.getOperator());
            handleInfo.setUserCode(doingTask.getOperator());
            SysUser sysUser = userService.selectUserByUserName(doingTask.getOperator());
            if (sysUser != null) {
                handleInfo.setUserName(sysUser.getNickName());
            }

            alarmClose.setHandleInfo(Collections.singletonList(handleInfo));
            try {
                MesResult<Void> mesResult = mesRequestService.alarmClose(alarmClose);
                if (!mesResult.isSuccess()) {
                    log.error("告警关闭请求-同步mes数据异常, 发生内容，{} 返回内容：{}", alarmClose, mesResult);
                }
                log.info("告警关闭请求-同步mes数据成功，返回内容：{}", mesResult);
            } catch (Exception e) {
                log.error("告警关闭请求-同步mes数据异常, 发生内容，{} 错误信息：{}", alarmClose, e.getMessage());
            }*/
        }
    }

    @Override
    public List<BaseAlarmRecord> getAlarmingByMaterialCode(String materialCode, AlarmTypeEnum alarmTypeEnum) {
        QueryWrapper<BaseAlarmRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(BaseAlarmRecord::getMaterialCode, materialCode)
                .eq(BaseAlarmRecord::getAlarmType, alarmTypeEnum.getCode())
                .isNull(BaseAlarmRecord::getAlarmEndTime);
        return list(queryWrapper);
    }

    @Override
    public AjaxResult alarmStatistics(DeviceFaultDto deviceFaultDto) {
        List<BaseAlarmRecord> list = list(new LambdaQueryWrapper<BaseAlarmRecord>().ge(deviceFaultDto.getStartTime() != null, BaseAlarmRecord::getAlarmEndTime, deviceFaultDto.getStartTime()).le(deviceFaultDto.getEndTime() != null, BaseAlarmRecord::getAlarmEndTime, deviceFaultDto.getEndTime()));
        Map<Integer, Long> map = list.stream().map(s -> s.getAlarmType()).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        return AjaxResult.success(map);
    }


    /**
     * 获取没有关闭的告警记录
     *
     * @param materialCode
     * @param alarmTypeEnum
     * @param businessInfo 业务信息（eg:产品编码）
     * @return java.util.List<com.cosmoplat.xikai.business.domain.BaseAlarmRecord>
     * @date 11:57 2025/1/15
     **/
    private List<BaseAlarmRecord> getNotCloseAlarm(String materialCode, AlarmTypeEnum alarmTypeEnum, String businessInfo) {
        QueryWrapper<BaseAlarmRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(BaseAlarmRecord::getMaterialCode, materialCode)
                .eq(BaseAlarmRecord::getAlarmType, alarmTypeEnum.getCode())
                .eq(StringUtils.isNotEmpty(businessInfo), BaseAlarmRecord::getBusinessInfo, businessInfo)
                .isNull(BaseAlarmRecord::getAlarmEndTime);
        return list(queryWrapper);
    }


}




